package com.abso.mp3tunes.locker.core.data;

import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.apache.commons.lang.math.NumberUtils;
import org.dom4j.Element;

/**
 * A set of utility methods to handle data returned from the Locker.
 */
public class LockerDataUtils {

	/** Private constructor (don't instantiate). */
	private LockerDataUtils() {
	}

	/**
	 * Extracts a string value from a XML element.
	 * 
	 * @param elem
	 *            the element whose string value must be returned.
	 * @param path
	 *            the XPath to be used to locate the value.
	 * @return the extracted string value.
	 */
	public static String getString(Element elem, String path) {
		return elem.valueOf(path);
	}

	/**
	 * Extracts an integer value from a XML element.
	 * 
	 * @param elem
	 *            the element whose integer value must be returned.
	 * @param path
	 *            the XPath to be used to locate the value.
	 * @param defaultValue
	 *            the default value to be returned if the string value located
	 *            through <i>path</i> cannot be converted to an integer.
	 * @return the extracted integer value.
	 */
	public static int getInt(Element elem, String path, int defaultValue) {
		return NumberUtils.toInt(elem.valueOf(path), defaultValue);
	}

	/**
	 * Extracts a double value from a XML element.
	 * 
	 * @param elem
	 *            the element whose double value must be returned.
	 * @param path
	 *            the XPath to be used to locate the value.
	 * @param defaultValue
	 *            the default value to be returned if the string value located
	 *            through <i>path</i> cannot be converted to a double.
	 * @return the extracted double value.
	 */
	public static double getDouble(Element elem, String path,
			double defaultValue) {
		return NumberUtils.toDouble(elem.valueOf(path), defaultValue);
	}

	/**
	 * Extracts a long integer value from a XML element.
	 * 
	 * @param elem
	 *            the element whose long integer value must be returned.
	 * @param path
	 *            the XPath to be used to locate the value.
	 * @param defaultValue
	 *            the default value to be returned if the string value located
	 *            through <i>path</i> cannot be converted to a long integer.
	 * @return the extracted long integer value.
	 */
	public static long getLong(Element elem, String path, long defaultValue) {
		return NumberUtils.toLong(elem.valueOf(path), defaultValue);
	}

	/**
	 * Extracts a date value from a XML element.
	 * 
	 * @param elem
	 *            the element whose date value must be returned.
	 * @param path
	 *            the XPath to be used to locate the value.
	 * @return the extracted date value, or <code>null</code> if the located
	 *         string value cannot be converted to a date.
	 */
	public static Date getDate(Element elem, String path) {
		String stringValue = elem.valueOf(path);
		if (stringValue.equals("")) {
			return null;
		}
		try {
			SimpleDateFormat parser = new SimpleDateFormat(
					"yyyy-MM-dd HH:mm:ss");
			return parser.parse(stringValue);
		} catch (ParseException e) {
			return null;
		}
	}

	/**
	 * Pretty prints a size in bytes.
	 * 
	 * @param size
	 *            the size (in bytes).
	 * @return a pretty printed value for the size.
	 */
	public static String getPrettyPrintedSize(long size) {
		StringBuffer buffer = new StringBuffer();
		NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
		if (format instanceof DecimalFormat) {
			((DecimalFormat) format).applyPattern("#,##0.00");
		}
		FieldPosition f = new FieldPosition(0);
		if ((size / (1024.0 * 1024)) > 1000) {
			format.format((size / (1024.0 * 1024 * 1024)), buffer, f);
			buffer.append(" GB (");
		} else {
			format.format((size / (1024.0 * 1024)), buffer, f);
			buffer.append(" MB (");
		}
		format = NumberFormat.getNumberInstance(Locale.US);
		if (format instanceof DecimalFormat) {
			((DecimalFormat) format).applyPattern("#,##0");
		}
		f = new FieldPosition(0);
		format.format(size, buffer, f);
		buffer.append(" bytes)");
		return buffer.toString();
	}

	/**
	 * Pretty prints a time length.
	 * 
	 * @param length
	 *            the time length (in milliseconds).
	 * @return a pretty printed value for the length.
	 */
	public static String getPrettyPrintedLength(double length) {
		long totSeconds = (long) length / 1000;
		long minutes = totSeconds / 60;
		long seconds = totSeconds % 60;
		return minutes + ":" + (seconds < 10 ? "0" + seconds : "" + seconds);
	}

	/**
	 * Returns the set of file keys for a specific set of tracks.
	 * 
	 * @param tracks
	 *            a set of tracks.
	 * @return the associated set of file keys.
	 */
	public static String[] getTrackKeys(Track[] tracks) {
		String[] keys = new String[tracks.length];
		for (int i = 0; i < tracks.length; i++) {
			keys[i] = tracks[i].getFileKey();
		}
		return keys;
	}

}
